package core

import (
	"errors"
	"fmt"
	"strconv"
	"strings"

	conf "github.com/qqliaoxin/jsonsql/conf"
	"github.com/qqliaoxin/jsonsql/db"
	"github.com/qqliaoxin/jsonsql/logger"
)

type UpdateMysqlExecutor struct {
	Table  string        `json:"table"`
	Join   string        `json:"join"`
	Set    string        `json:"set"`
	Where  string        `json:"where"`
	Sql    string        `json:"sql"`
	Params []interface{} `json:"params"`
	Select string        `json:"select"`
}

type JsonUpdateSqlExecutor struct {
	SqlJon         map[string]*SqlJon              `json:"sqlJon"`         //内关联查询Table结构
	TableUpdateSql map[string]*UpdateMysqlExecutor `json:"tableUpdateSql"` //更新内容集
	Data           map[string]interface{}          `json:"data"`           //查询返回数据集
	config         *conf.Config                    //读取配置
	Err            error                           `json:"err"`
}

func NewUpdateJsonSQL(ctx map[string]interface{}) *JsonSqlExecutor {
	njsql := NewUpdateJsonSqlExecutor()
	if njsql.Err == nil {
		njsql.Err = njsql.doUpdateSortedMap(ctx)
	}
	return njsql
}

// 创建Update构造体
func NewUpdateJsonSqlExecutor() *JsonSqlExecutor {
	conf := conf.ReadJsonConfig()
	jsonUpdateSqlExecutor := &JsonSqlExecutor{
		SqlJon:         make(map[string]*SqlJon),
		TableUpdateSql: make(map[string]*UpdateMysqlExecutor),
		TableSql:       make(map[string]*GetMysqlExecutor),
		Data:           make(map[string]interface{}),
	}
	if len(conf.Table) == 0 {
		jsonUpdateSqlExecutor.Err = errors.New("Config no init Table list!")
		return jsonUpdateSqlExecutor
	}
	jsonUpdateSqlExecutor.config = conf
	return jsonUpdateSqlExecutor
}

// json map 数据分组
func (e *JsonSqlExecutor) doUpdateSortedMap(ctx map[string]interface{}) error {
	sqlJon := make(map[string]interface{})
	table := make(map[string]interface{})
	// 数据分组
	for key, value := range ctx {
		// key表示的是table，value{}
		if strings.HasSuffix(key, "@") && strings.Index(key, "|") < 0 {
			sqlJon[key] = value
		} else {
			table[key] = value
		}
	}
	logger.Debugf("doUpdateSortedMap")
	// 先生成 @ 引用关联
	if len(sqlJon) > 0 {
		sortedMap(sqlJon, func(k string, v interface{}) {
			// fmt.Printf("jon::Key:%+v\n", k)
			if jon, ok := v.(map[string]interface{}); ok {
				jm := &SqlJon{}
				e.createSql(jon)
				jm.Table = jon
				for k, _ := range jon {
					jm.Sql = e.TableSql[k].Sql
					jm.Params = e.TableSql[k].Params
					delete(e.TableSql, k)
				}
				e.SqlJon[k] = jm //放到内关联组
			}
		})
	}
	// 正常 Update table 生成处理
	if len(table) > 0 {
		err = e.createUpdateSql(table)
		if err != nil {
			return err
		}
	}
	// 执行更新
	err = e.UpdateSql()
	if err != nil {
		return err
	}

	return nil
}

// 构造 SQL 开始 ctx 构造的对象, exeSql 是否是要执行sql 语句. sql@ 并不需要执行，只生成sql语句。
func (e *JsonSqlExecutor) createUpdateSql(ctx map[string]interface{}) error {
	for t, v := range ctx {
		// 构造 table
		err = e.toUpdateTable(t, v)
		if err != nil {
			return err
		}
		// 构造 where 查询条件
		err = e.toMakeUpdateWhere(t, v)
		if err != nil {
			return err
		}
	}
	return nil
}

// Table 表转化
func (e *JsonSqlExecutor) toUpdateTable(t string, val interface{}) error {
	tables := strings.Split(t, "|")
	//HasPrefix 判断字符串 s 是否以 prefix 开头：
	//HasSuffix 判断字符串 s 是否以 suffix 结尾：
	//表数组 table
	m := &UpdateMysqlExecutor{}
	for i := 0; i < len(tables); i++ {
		//判断元素是否在配置数组当中
		if _, ok := e.config.Table[tables[i]]; ok {
			m.Table += fmt.Sprintf(" %s AS %s", e.config.Table[tables[i]].TableName, tables[i])
			if i == len(tables)-1 {
				m.Table += ""
			} else {
				m.Table += ","
			}
		} else {
			// @ 引用表处理
			if strings.HasSuffix(tables[i], "@") {
				if _sql_t, ok := e.SqlJon[tables[i]]; ok {
					m.Table += fmt.Sprintf(" (%s) AS %s", _sql_t.Sql, strings.ToLower(tables[i][:len(tables[i])-1]))
					m.Params = append(m.Params, _sql_t.Params...) //多引用 @ 条件 params 值问题解决
				}
			} else {
				return errors.New(fmt.Sprintf("Table [%s] is no exit;", tables[i]))
			}
		}
	}

	e.TableUpdateSql[t] = m
	return nil
}

//核心 Update 业务逻辑处理
func (e *JsonSqlExecutor) toMakeUpdateWhere(t string, val interface{}) error {
	if vals, ok := val.(map[string]interface{}); ok {
		for k, v := range vals {
			if strings.HasPrefix(k, "@") {
				switch k {
				case "@j":
					e.toUpdateJoin(t, v)
				case "@join":
					e.toUpdateJoin(t, v)
				case "@s":
					e.toUpdateSet(t, v)
				case "@set":
					e.toUpdateSet(t, v)
				case "@w":
					e.toUpdateWhere(t, v)
				case "@where":
					e.toUpdateWhere(t, v)
				default:
					return errors.New(fmt.Sprintf("The [%s] is no exit;", k))
				}
			}
		}
		// 生成sql语句
		e.toUpdateSql(t)
	}
	return nil
}

func (e *JsonSqlExecutor) toUpdateJoin(t string, jVal interface{}) error {
	m := e.TableUpdateSql[t]
	if val, ok := jVal.(map[string]interface{}); ok {
		// 控制map执行顺序
		for i := 1; i <= len(val); i++ {
			jV := val[strconv.Itoa(i)].(map[string]interface{})
			// 1.添加JOIN类型
			m.Join += " JOIN"
			if jType := fmt.Sprintf("%v", jV["type"]); jType != "" {
				m.Join += strings.ToUpper(" " + jType)
			}
			// 2.处理"@"和"/"，添加table
			jTable := fmt.Sprintf("%v", jV["table"])
			if a := strings.Index(jTable, "@"); a > 0 {
				_sql := jTable[:a+1]
				if _sql_t, ok := e.SqlJon[_sql]; ok {
					if b := strings.HasPrefix(jTable[a+1:], "/"); b {
						m.Join += fmt.Sprintf(" (%s) AS %s ", _sql_t.Sql, jTable[a+2:])
					} else {
						m.Join += fmt.Sprintf(" (%s) AS table[%d] ", _sql_t.Sql, i)
					}
				}
			} else {
				if a := strings.Index(jTable, "/"); a > 0 {
					m.Join += fmt.Sprintf(" %s AS %s ", jTable[:a], jTable[a+1:])
				} else {
					if _, ok := e.config.Table[jTable]; ok {
						m.Join += fmt.Sprintf(" %s AS %s ", e.config.Table[jTable].TableName, jTable)
					} else {
						return errors.New(fmt.Sprintf("Table [%s] is no exit;", jTable))
					}
				}
			}
			// 3.添加condition
			m.Join += "ON "
			jCons := strings.Split(fmt.Sprintf("%v", jV["condition"]), ",")
			for i, jCon := range jCons {
				m.Join += strings.Replace(jCon, "/", ".", 1)
				if i < len(jCons)-1 {
					m.Join += "="
				}
			}
		}
	}
	return nil
}

// set 字段处理
func (e *JsonSqlExecutor) toUpdateSet(t string, sVal interface{}) error {
	m := e.TableUpdateSql[t]
	if set, ok := sVal.(map[string]interface{}); ok {
		firstFlag := true
		for k, v := range set {
			// 处理key
			if strings.HasSuffix(k, "@") {
				if a := strings.Index(k[:len(k)-1], "/"); a > 0 {
					k = strings.ReplaceAll(k[:len(k)-1], "/", ".")
				}
			}
			// 处理逗号
			if firstFlag {
				firstFlag = false
			} else {
				m.Set += ", "
			}
			// 处理value
			if val, ok := v.(string); ok {
				if a := strings.Index(val, "@"); a > 0 {
					_sql := val[:a+1]
					m.Set += fmt.Sprintf("%s = (%s) ", k, e.SqlJon[_sql].Sql)
				} else if b := strings.Index(val, "/"); b > 0 {
					val = strings.ReplaceAll(val, "/", ".")
					m.Set += k + " = " + val
				} else {
					m.Set += k + " = ?"
					m.Params = append(m.Params, v)
				}
			} else {
				m.Set += k + " = ?"
				m.Params = append(m.Params, v)
			}
		}
		m.Set = strings.TrimRight(m.Set, ",")
	}
	return nil
}

func (e *JsonSqlExecutor) toUpdateWhere(t string, wVal interface{}) error {
	w := e.TableUpdateSql[t]
	andFirst := true
	where := make(map[string]interface{})
	if mw, ok := wVal.(map[string]interface{}); ok {
		for k, v := range mw {
			// 优先处理没有 $ | 的条件,解决map 无序不好控制问题。
			if !strings.HasPrefix(k, "&") && !strings.HasPrefix(k, "|") {
				if andFirst {
					w.Where += fmt.Sprintf(" %s", e.makeUpdateWhere(t, k, v))
					andFirst = false
				} else {
					w.Where += fmt.Sprintf(" AND %s", e.makeUpdateWhere(t, k, v))
				}
			} else {
				where[k] = v
			}
		}
	}

	// 其它的条件处理
	for k, v := range where {
		if strings.HasPrefix(k, "&") {
			w.Where += fmt.Sprintf(" AND %s", e.makeUpdateWhere(t, k[1:], v))
		} else if strings.HasPrefix(k, "|") {
			w.Where += fmt.Sprintf(" OR %s", e.makeUpdateWhere(t, k[1:], v))
		}
	}

	return nil
}

// where column 逻辑处理 Key
func (e *JsonSqlExecutor) makeUpdateWhere(t string, k string, wcVal interface{}) string {
	m := e.TableUpdateSql[t]
	if strings.HasSuffix(k, "@") {
		// key 处理
		a := strings.Index(k[:len(k)-1], "/")
		if a > 0 {
			return fmt.Sprintf(" %s.%s = %s", strings.ToLower(k[:a]), k[a+1:len(k)-1], e.makeUpdateWhereToTableORColumnt(t, wcVal))
		} else if _sql_t, ok := e.SqlJon[wcVal.(string)]; ok {
			m.Params = append(m.Params, _sql_t.Params...)
			return fmt.Sprintf(" %s IN (%s)", k[:len(k)-1], _sql_t.Sql)
		} else {
			return fmt.Sprintf(" %s = %s", k[:len(k)-1], e.makeUpdateWhereToTableORColumnt(t, wcVal))
		}
	} else if strings.HasSuffix(k, "[]") {
		if wcV, ok := wcVal.(string); ok {
			if strings.HasSuffix(wcV, "@") {
				if _sql_t, ok := e.SqlJon[wcV]; ok {
					m.Params = append(m.Params, _sql_t.Params...)
					return fmt.Sprintf(" %s IN (%s)", k[:len(k)-2], _sql_t.Sql)
				}
			}
		} else {
			inStr := strings.Join(parseIntListString(wcVal), ",")
			return fmt.Sprintf(" %s IN (%s)", k[:len(k)-2], inStr)
		}
	} else if strings.HasSuffix(k, "%") {
		m.Params = append(m.Params, wcVal)
		return fmt.Sprintf(" %s LIKE '%s?%s'", k[:len(k)-1], "%", "%")
	} else if strings.HasSuffix(k, ">") {
		m.Params = append(m.Params, wcVal)
		return fmt.Sprintf(" %s > ?", k[:len(k)-1])
	} else if strings.HasSuffix(k, ">=") {
		m.Params = append(m.Params, wcVal)
		return fmt.Sprintf(" %s >= ?", k[:len(k)-2])
	} else if strings.HasSuffix(k, "<") {
		m.Params = append(m.Params, wcVal)
		return fmt.Sprintf(" %s < ?", k[:len(k)-1])
	} else if strings.HasSuffix(k, "<=") {
		m.Params = append(m.Params, wcVal)
		return fmt.Sprintf(" %s <= ?", k[:len(k)-1])
	} else {
		m.Params = append(m.Params, wcVal)
		return fmt.Sprintf(" %s = ?", k)
	}
	return ""
}

func (e *JsonSqlExecutor) makeUpdateWhereToTableORColumnt(t string, wcVal interface{}) string {
	m := e.TableUpdateSql[t]
	// @引用 value 处理
	if wcV, ok := wcVal.(string); ok {
		b := strings.Index(wcV, "/")
		if b > 0 {
			return fmt.Sprintf("%s.%s", strings.ToLower(wcV[:b]), wcV[b+1:len(wcV)])
		} else {
			m.Params = append(m.Params, wcVal)
			return "?"
		}
	} else {
		m.Params = append(m.Params, parseNum(wcVal))
		return "?"
	}
}

func (e *JsonSqlExecutor) toUpdateSql(t string) error {
	m := e.TableUpdateSql[t]
	m.Sql = "UPDATE"
	if m.Table != "" {
		m.Sql += m.Table
	}

	if m.Join != "" {
		m.Sql += m.Join
	}

	if len(m.Set) > 0 {
		m.Sql += " SET "
		m.Sql += m.Set
	}

	if len(m.Where) > 0 {
		m.Sql += " WHERE"
		m.Sql += m.Where
	}
	return nil
}

// 执行查询
func (e *JsonSqlExecutor) UpdateSql() error {
	for table, _ := range e.TableUpdateSql {
		m := e.TableUpdateSql[table]
		if e.config.Debug {
			logger.Info("*************************************************************************")
			logger.Debugf("params: %v", m.Params...)
			logger.Debugf("%s", m.Sql)
			logger.Info("*************************************************************************")
		}
		data, err := db.Update(m.Sql, m.Params...)
		if err != nil {
			return errors.New(fmt.Sprintf("Update err: %s", err.Error()))
		}
		e.Data[table] = data
	}
	return nil
}
